﻿using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;

namespace ayxjDllClass
{
    /// <summary>
    /// 卫星可跟踪时间段
    /// </summary>
    public class DateRange
    {
        public DateTime startDT { get; set; }
        public DateTime stopDT { get; set; }

        private List<SatelliteLocation> instantaneousSatelliteLocation = new List<SatelliteLocation>();
        /// <summary>
        /// 每个时间点的瞬间卫星位置
        /// </summary>
        public List<SatelliteLocation> InstantaneousSatelliteLocation
        {
            get { return instantaneousSatelliteLocation; }
            set { instantaneousSatelliteLocation = value; }
        }
        /// <summary>
        /// 解算卫星位置的时间间隔
        /// </summary>
        public int timeSpan { get; set; }
        public DateRange()
        {
            startDT = stopDT = DateTime.Parse("1970-01-01 00:00:00");
            timeSpan = 10;//10ms
        }
    }

    /// <summary>
    /// 卫星时间位置对应关系
    /// </summary>
    public class SatelliteLocation
    {
        public DateTime nowTime { get; set; }
        public double nowAZ { get; set; }
        public double nowEL { get; set; }
        public double circleNum { get; set; }

        public SatelliteLocation()
        {
            nowTime = DateTime.Now;
        }
    }
    /// <summary>
    /// 信息解算
    /// </summary>
    public class ayxjClass
    {
    
       
        public struct info
        {
            public string Name;
            public string Line1;
            public string Line2;
            public double m_Lat;
            public double m_Lon;
            public double m_Alt;
            public double t_Minute;
        };
        public class degInfo
        {
            public double degAz;
            public double degEl;
            public double degX;
            public double degY;
        };

       //获取当前角度
        [DllImport("TleCompute.dll", EntryPoint = "GetPosition", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern bool GetPosition(out double d1, out double d2, out double d3, out double d4, string Name, string Line1, string Line2, double m_Lat, double m_Lon, double m_Alt, double t_Minute);
        
        //星历解算时年份分析计算卫星发射至今分钟数
        [DllImport("TleCompute.dll", EntryPoint = "GetMinute", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern double GetMinute(int nian, int znian, double days, double zdays, int daq);


        [DllImport("TleCompute.dll", EntryPoint = "CalculateSatellite", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern bool CalculateSatellite(double Lon1, double Lat1, double Lon2, out double A, out double E, out double P);

        #region 属性

        #endregion
        /// <summary>
        /// 星历解算时年份分析计算卫星发射至分钟数
        /// </summary>
        /// <param name="nian">当前年份后两位</param>
        /// <param name="znian">星历年份后两位</param>
        /// <param name="days">当前年份天数</param>
        /// <param name=" zdays">星历年份天数</param>
        /// <param name="daq">当前时间</param>
        /// <returns>卫星发射至今分钟数</returns>
        public static double years(int nian, int znian, double days, double zdays, DateTime daq)
        {
            if (nian != znian)
            {
                int year = checked(daq.Year - 1);
                if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
                {
                    return (days + (366.0 - zdays)) * 1440.0;
                }
                return (days + (365.0 - zdays)) * 1440.0;
            }
            return (days - zdays) * 1440.0;
        }
        /// <summary>
        /// 星历生命周期分钟数
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private static double minutesSpan(DateTime dt, int UTC,string firstLinePara)
        {
            double minutes = 0;

            dt = dt.AddHours(-UTC);//东8区
            int znian = Convert.ToInt32(firstLinePara.Substring(18, 2));
            int nianStop = Convert.ToInt32(dt.ToString().Substring(2, 2));
            double zdays = Convert.ToDouble(firstLinePara.Substring(20, 12));
            double daysStop = Convert.ToDouble(
                      (double)dt.DayOfYear
                    + (double)dt.Hour / 24.0
                    + (double)dt.Minute / 1440.0
                    + (double)dt.Second / 86400.0
                    + (double)dt.Millisecond / 86400000.0);

            minutes = years(nianStop, znian, daysStop, zdays, dt);//星历生命当前分钟数

            return minutes;

        }



        #region 由星历计算某地天线可跟踪时间段
        /// <summary>
        /// 由星历计算某地天线可跟踪时间段
        /// </summary>
        /// <param name="str0">星历名</param>
        /// <param name="str1">第一行根数</param>
        /// <param name="str2">第二行根数</param>
        /// <param name="dbWD">站点北纬</param>
        /// <param name="dbJD">站点东经</param>
        /// <param name="dbGD">站点海拔高</param>
        /// <param name="daq">开始解算时间</param>
        /// <param name="UTC">时区设置</param>
        /// <param name="day">解算天数</param>
        /// <returns>开始结束时间段及对应角度圈次</returns>
        public static ArrayList timeInterval(string str0, string str1, string str2, double dbWD, double dbJD, double dbGD, DateTime daq, int UTC, int day)
        {
            double time;//时间
            daq = daq.AddHours(-UTC);//设置为UTC时间
            double[] fwfy = new double[2];//解算角度数组
            ArrayList timeDatas = new ArrayList(1); //数据保存
            int znian = Convert.ToInt32(str1.Substring(18, 2));//轨道预报的历元年后两位
            double zdays = Convert.ToDouble(str1.Substring(20, 12));//轨道预报的历元时刻
            double dbQc = Convert.ToDouble(str2.Substring(63, 5));//历元轨道数
            int nian = Convert.ToInt32((daq.Year).ToString().Substring(2));//当前年份后两位
            double days = Convert.ToDouble((daq.DayOfYear + daq.Hour / 24.000000000 + daq.Minute / 1440.000000000 + daq.Second / 86400.000000000 + daq.Millisecond / 86400000.000000000));//本年至今天数
            double shiC = years(nian, znian, days, zdays, daq);//至星历时刻后至今分钟数
            DateTime time1 = new DateTime(daq.Year, 1, 1);
            if (nian != znian) { time1 = time1.AddYears(-1).AddDays(zdays - 1); } else { time1 = time1.AddDays(zdays - 1); }
            //
            string[] all = new string[4];//单条信息数组
            string[] alls = new string[(86400 * day) + 1]; ;//所有信息
            for (int i = 0; i < (86400 * day); i++)
            {
                time = shiC + i / 60.0000;//分钟数
                degInfo info = new degInfo();
                GetPosition(out fwfy[0], out fwfy[1], out info.degX, out info.degY, str0, str1, str2, dbWD, dbJD, dbGD, time);
                all[0] = time1.AddDays(time / 1440).ToString("yyyy-MM-dd HH:mm:ss:fff");
                all[1] = fwfy[0].ToString("000.00000000");//方位
                all[2] = fwfy[1].ToString("00.00000000");//俯仰
                alls[i] = string.Join(",", all);
            }
            //
            string[] zll = new string[4];
            for (int i = 0; i < (86400 * day - 2); i++)  //读入数据并赋予数组
            {
                if (Convert.ToDouble(alls[i].Substring(37, 10)) < 0 && Convert.ToDouble(alls[i + 1].Substring(37, 10)) > 0)
                {
                    DateTime daqK = Convert.ToDateTime(alls[i].Substring(0, 19));
                    int nianK = Convert.ToInt32(daqK.ToString().Substring(2, 2));
                    double daysK = Convert.ToDouble((daqK.DayOfYear + daqK.Hour / 24.000000000 + daqK.Minute / 1440.000000000 + daqK.Second / 86400.000000000 + daqK.Millisecond / 86400000.000000000));//本年至今天数
                    shiC = years(nianK, znian, daysK, zdays, daqK);
                    for (int k = 0; k < 30000; k++)
                    {
                        time = shiC + k / 60000.0000;//分钟数
                        degInfo info = new degInfo();
                        GetPosition(out fwfy[0], out fwfy[1], out info.degX, out info.degY, str0, str1, str2, dbWD, dbJD, dbGD, time);
                        if (fwfy[1] >= 0)
                        {
                            zll[0] = time1.AddDays(time / 1440).AddHours(UTC).ToString("yyyy-MM-dd HH:mm:ss:fff");
                            zll[1] = info.degX.ToString("000.00000000");//方位
                            zll[2] = info.degX.ToString("00.00000000");//俯仰
                            zll[3] = (dbQc + ((Convert.ToDouble(str2.Substring(52, 11)) / 1440.00000000) * time)).ToString("00.00000000");//当前圈次
                            timeDatas.Add("开始时间:" + zll[0] + ",X:" + zll[1] + ",Y轴:" + zll[2] + ",圈次:" + zll[3] + "\r\n");
                            break;
                        }
                    }
                }
                else if (Convert.ToDouble(alls[i].Substring(37, 10)) > 0 && Convert.ToDouble(alls[i + 1].Substring(37, 10)) < 0)
                {
                    DateTime daqJ = Convert.ToDateTime(alls[i].Substring(0, 19));
                    int nianJ = Convert.ToInt32(daqJ.ToString().Substring(2, 2));
                    double daysJ = Convert.ToDouble((daqJ.DayOfYear + daqJ.Hour / 24.000000000 + daqJ.Minute / 1440.000000000 + daqJ.Second / 86400.000000000 + daqJ.Millisecond / 86400000.000000000));
                    shiC = years(nianJ, znian, daysJ, zdays, daqJ);
                    for (int k = 0; k < 30000; k++)
                    {
                        time = shiC + k / 60000.0000;
                        degInfo info = new degInfo();
                        GetPosition(out fwfy[0], out fwfy[1], out info.degX, out info.degY, str0, str1, str2, dbWD, dbJD, dbGD, time);
                        if (fwfy[1] < 0)
                        {
                            time = shiC + (k - 1) / 60000.0000;
                            GetPosition(out fwfy[0], out fwfy[1], out info.degX, out info.degY, str0, str1, str2, dbWD, dbJD, dbGD, time);
                            zll[0] = time1.AddDays(time / 1440).AddHours(UTC).ToString("yyyy-MM-dd HH:mm:ss:fff");
                            zll[1] = info.degX.ToString("000.00000000");//方位
                            zll[2] = info.degY.ToString("00.00000000");//俯仰
                            zll[3] = (dbQc + ((Convert.ToDouble(str2.Substring(52, 11)) / 1440.00000000) * time)).ToString("00.00000000");//当前圈次
                            timeDatas.Add("结束时间:" + zll[0] + ",X轴:" + zll[1] + ",Y轴:" + zll[2] + ",圈次:" + zll[3] + "\r\n");
                            break;
                        }
                    }
                }
            }
            if (timeDatas[0].ToString().Substring(0, 4) == "结束时间") { timeDatas.RemoveAt(0); }
            return timeDatas;
        }
        /// <summary>
        /// 由星历计算某地天线某时间段对应时刻跟踪角度
        /// </summary>
        /// <param name="str0">星历名</param>
        /// <param name="str1">第一行根数</param>
        /// <param name="str2">第二行根数</param>
        /// <param name="dbWD">站点北纬</param>
        /// <param name="dbJD">站点东经</param>
        /// <param name="dbGD">站点海拔高</param>
        /// <param name="ksTime">开始解算时间</param>
        /// <param name="jsTime">结束解算时间</param>
        /// <param name=" timeInterval">解算间隔(ms)</param>
        /// <param name="UTC">时区设置</param>
        /// <returns>对应时间角度</returns>
        public static ArrayList timeAngle(string str0, string str1, string str2, double dbWD, double dbJD, double dbGD, DateTime ksTime, DateTime jsTime, int timeInterval, int UTC)
        {
            ArrayList timeDatas = new ArrayList(1); //数据保存
            string[] all = new string[3];//单条信息数组
            double time;//时间
            double[] fwfy = new double[2];//解算角度数组
            ksTime = ksTime.AddHours(-UTC);//设置为UTC时间
            jsTime = jsTime.AddHours(-UTC);//设置为UTC时间
            int znian = Convert.ToInt32(str1.Substring(18, 2));//轨道预报的历元年后两位
            double zdays = Convert.ToDouble(str1.Substring(20, 12));//轨道预报的历元时刻

            int nian1 = Convert.ToInt32((ksTime.Year).ToString().Substring(2));//开始年份后两位
            double days1 = Convert.ToDouble((ksTime.DayOfYear + ksTime.Hour / 24.000000000 + ksTime.Minute / 1440.000000000 + ksTime.Second / 86400.000000000 + ksTime.Millisecond / 86400000.000000000));//开始时间至今天数
            double shiC = years(nian1, znian, days1, zdays, ksTime);//至星历时刻后至开始时间分钟数
            int nian2 = Convert.ToInt32((jsTime.Year).ToString().Substring(2));//结束年份后两位
            double days2 = Convert.ToDouble((jsTime.DayOfYear + jsTime.Hour / 24.000000000 + jsTime.Minute / 1440.000000000 + jsTime.Second / 86400.000000000 + jsTime.Millisecond / 86400000.000000000));//结束时间至今天数
            double shiC2 = years(nian2, znian, days2, zdays, jsTime);//至星历时刻后至结束时间分钟数
            DateTime time1 = new DateTime(ksTime.Year, 1, 1);
            if (nian1 != znian) { time1 = time1.AddYears(-1).AddDays(zdays - 1); } else { time1 = time1.AddDays(zdays - 1); }
            //
            time = shiC;
            for (int i = 0;; i++)
            {
                if (time >= shiC2) { break; }
                time = shiC + (i / 60000.00000000000) * timeInterval; //分钟数
                degInfo info = new degInfo();
                GetPosition(out fwfy[0], out fwfy[1], out info.degX, out info.degY, str0, str1, str2, dbWD, dbJD, dbGD, time);
                all[0] = time1.AddDays(time / 1440).AddHours(UTC).ToString("yyyy年MM月dd日HH时mm分ss.fff秒");
                all[1] = info.degX.ToString("000.00000000");//方位
                all[2] = info.degY.ToString("00.000000000");//俯仰
                timeDatas.Add(string.Join(",", all));
            }
            return timeDatas;
        }

        #endregion
       

       

        #region 获取本地IPv4地址
        /// <summary>
        /// 获取本地IPv4地址
        /// </summary>
        /// <returns></returns>
        public IPAddress GetLocalIPv4Address()
        {
            IPAddress localIpv4 = null;
            //获取本机所有的IP地址列表
            IPAddress[] IpList = Dns.GetHostAddresses(Dns.GetHostName());
            //循环遍历所有IP地址
            foreach (IPAddress IP in IpList)
            {
                //判断是否是IPv4地址
                if (IP.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIpv4 = IP;
                }
                else
                {
                    continue;
                }
            }
            return localIpv4;
        }
        #endregion

       
    }

    /// <summary>
    /// 窗口自适应
    /// </summary>
    public class windowAdaptation
    {
        /// <summary>
        /// 定义当前窗体的宽度,初始化窗口时设置
        /// </summary>
        public static float x;
        /// <summary>
        /// 定义当前窗体的高度,初始化窗口时设置
        /// </summary>
        public static float y;
        /// <summary>
        /// 获取窗口属性,初始化窗口时调用
        /// </summary>
        /// <param name="cons">当前窗口</param>
        public static void setTag(Control cons)
        {
            foreach (Control con in cons.Controls)
            {
                con.Tag = con.Width + ";" + con.Height + ";" + con.Left + ";" + con.Top + ";" + con.Font.Size;
                if (con.Controls.Count > 0)
                {
                    setTag(con);
                }
            }
        }
        /// <summary>
        /// 遍历窗体中控件并重新设置控件的值,调整窗口大小时调用
        /// </summary>
        /// <param name="newx">=当前窗口宽度值/初始化窗口宽度</param>
        /// <param name="newy">=当前窗口高度值/初始化窗口高度</param>
        /// <param name="cons">当前窗口</param>
        public static void setControls(float newx, float newy, Control cons)
        {
            //遍历窗体中的控件，重新设置控件的值
            foreach (Control con in cons.Controls)
            {
                //获取控件的Tag属性值，并分割后存储字符串数组
                if (con.Tag != null)
                {
                    string[] mytag = con.Tag.ToString().Split(new char[] { ';' });
                    //根据窗体缩放的比例确定控件的值
                    con.Width = Convert.ToInt32(System.Convert.ToSingle(mytag[0]) * newx);//宽度
                    con.Height = Convert.ToInt32(System.Convert.ToSingle(mytag[1]) * newy);//高度
                    con.Left = Convert.ToInt32(System.Convert.ToSingle(mytag[2]) * newx);//左边距
                    con.Top = Convert.ToInt32(System.Convert.ToSingle(mytag[3]) * newy);//顶边距
                    Single currentSize = System.Convert.ToSingle(mytag[4]) * newy;//字体大小
                    con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
                    if (con.Controls.Count > 0)
                    {
                        setControls(newx, newy, con);
                    }
                }
            }
        }
    }

    /// <summary>
    /// PID控制
    /// </summary>
    public class PID
    {
        /// <summary>
        /// PID控制相关参数
        /// </summary>
        public struct csPID
        {
            /// <summary>
            /// Kp系数
            /// </summary>
            public double P;
            /// <summary>
            ///Ki系数
            /// </summary>
            public double I;
            /// <summary>
            ///Kd系数
            /// </summary>
            public double D;
            /// <summary>
            ///位置式PID积分项
            /// </summary>
            public double Integral;
            /// <summary>
            ///位置式PID积分项最大值，用于限幅
            /// </summary>
            public double IntegralMax;
            /// <summary>
            ///前一次误差
            /// </summary>
            public double LastError;
            /// <summary>
            ///前两次误差
            /// </summary>
            public double PrevError;
            /// <summary>
            ///位置式PID输出最大值，用于限幅
            /// </summary>
            public double OutputMax;
        }


        /// <summary>
        /// 位置式PID控制
        /// </summary>
        /// <param name="pid">构造参数</param>
        /// <param name="NowValue">当前值</param>
        /// <param name="AimValue">目标值</param>
        /// <returns>PID控制值</returns>
        public static double PID_Cal(csPID pid, double NowValue, double AimValue)
        {
            double iError;   //当前误差
            double Output;    //控制输出
            iError = AimValue - NowValue;  //计算当前误差
            pid.Integral += pid.I * iError;	            //位置式PID积分项累加
            pid.Integral = pid.Integral > pid.IntegralMax ? pid.IntegralMax : pid.Integral;  //积分项上限幅
            pid.Integral = pid.Integral < -pid.IntegralMax ? -pid.IntegralMax : pid.Integral; //积分项下限幅
            Output = pid.P * iError + pid.Integral + pid.D * (iError - pid.LastError);
            Output = Output > pid.OutputMax ? pid.OutputMax : Output;  //控制输出上限幅
            Output = Output < -pid.OutputMax ? -pid.OutputMax : Output; //控制输出下限幅
            pid.LastError = iError;	//更新上次误差，用于下次计算 
            return Output;	//返回控制输出值
        }


        /// <summary>
        /// 增量式PID计算
        /// </summary>
        /// <param name="pid">构造参数</param>
        /// <param name="NowValue">当前值</param>
        /// <param name="AimValue">目标值</param>
        /// <returns>PID控制值</returns>
        public static double IncPIDCal(csPID pid, double NowValue, double AimValue)
        {
            double iError;   //当前误差
            double Output;    //控制输出
            iError = AimValue - NowValue;  //计算当前误差
            Output = pid.P * (iError - pid.LastError) + pid.I * iError + pid.D * (iError - pid.LastError * 2 + pid.PrevError);
            pid.PrevError = pid.LastError;         //存储误差，用于下次计算
            pid.LastError = iError;
            Output = Output > pid.OutputMax ? pid.OutputMax : Output;  //控制输出上限幅
            Output = Output < -pid.OutputMax ? -pid.OutputMax : Output; //控制输出下限幅
            return Output;                         //返回增量值
        }
    }
}
